Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ

Node / meshtastic / Meshtastic-Android / files / docs / en / developer / architecture.md

Displaying Rendered β€’ View raw β€’ Download

docs/en/developer/architecture.md ba63f5911a128c8a9bd2a8cdb567a76f09df7e01 (ba63f591) Text, 7.82 KB

title: Architecture
parent: Developer Guide
nav_order: 1
last_updated: 2026-06-11
aliases:
β€’ layers
β€’ module-architecture
β€’ kmp
β€’ radio-control

Architecture

The Meshtastic Android and Desktop apps follow a modular Kotlin Multiplatform (KMP) architecture with clear layer boundaries (iOS is currently a compile-only validation target β€” there is no shipping iOS app yet).

Layer Overview

T282828
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ androidApp / desktopApp β”‚ Platform entry points
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ feature/* modules β”‚ UI + Business Logic
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ core/* modules β”‚ Shared infrastructure
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Platform (Android/JVM/iOS) β”‚ OS-specific bindings
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Module Categories

T383838androidApp/ β€” Android Application

The Android application entry point:
β€’ Activity, Application, and Manifest definitions
β€’ Koin DI module composition (T383838AppKoinModule)
β€’ Flavor-specific bindings (T383838google/, T383838fdroid/)
β€’ Android-only integrations (widgets, services)

T383838desktopApp/ β€” Desktop JVM Application

The Desktop (Linux/macOS/Windows) entry point:
β€’ Compose Desktop window management
β€’ Desktop-specific DI (T383838DesktopKoinModule)
β€’ Platform stubs for Android-only capabilities
β€’ BLE (Kable), Serial, and TCP transport implementations

T383838feature/* β€” Feature Modules

Each T383838feature/ module owns a vertical slice of functionality:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Module β”‚ Responsibility β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T383838feature:intro β”‚ Onboarding/welcome flow β”‚
β”‚ T383838feature:messaging β”‚ Messages, channels, contacts, quick chat β”‚
β”‚ T383838feature:connections β”‚ Bluetooth/USB/TCP connection management β”‚
β”‚ T383838feature:map β”‚ Map display, waypoints β”‚
β”‚ T383838feature:node β”‚ Node list, node detail, metrics β”‚
β”‚ T383838feature:settings β”‚ All configuration screens β”‚
β”‚ T383838feature:firmware β”‚ Firmware update flow β”‚
β”‚ T383838feature:docs β”‚ In-app documentation browser β”‚
β”‚ T383838feature:wifi-provision β”‚ WiFi provisioning β”‚
β”‚ T383838feature:widget β”‚ Android home screen widgets β”‚
β”‚ T383838feature:discovery β”‚ Mesh network discovery β”‚
β”‚ T383838feature:car β”‚ Android Auto / Car App Library β€” google flavor only, conditionally reg… β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Feature modules:
β€’ Use the T383838meshtastic.kmp.feature convention plugin
β€’ Depend on T383838core modules, never on other T383838feature modules
β€’ Own their navigation entries and DI registrations
β€’ Contain platform-specific implementations in T383838androidMain/T383838jvmMain/T383838iosMain

T383838core/* β€” Core Modules

Shared infrastructure used by all features:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Module β”‚ Responsibility β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T383838core:common β”‚ Utilities, extensions, build config β”‚
β”‚ T383838core:navigation β”‚ Routes, deep links, Navigation 3 β”‚
β”‚ T383838core:ui β”‚ Shared Compose components, icons, theme β”‚
β”‚ T383838core:resources β”‚ Shared string resources β”‚
β”‚ T383838core:model β”‚ Domain models β”‚
β”‚ T383838core:data β”‚ Data layer abstractions β”‚
β”‚ T383838core:domain β”‚ Use cases / business logic β”‚
β”‚ T383838core:database β”‚ Room KMP database β”‚
β”‚ T383838core:datastore β”‚ DataStore preferences β”‚
β”‚ T383838core:prefs β”‚ App preferences β”‚
β”‚ T383838core:repository β”‚ Repository interfaces β”‚
β”‚ T383838core:service β”‚ Mesh service layer β”‚
β”‚ T383838core:di β”‚ DI utilities β”‚
β”‚ T383838core:network β”‚ HTTP/serial/transport β”‚
β”‚ T383838core:ble β”‚ Bluetooth LE abstractions β”‚
β”‚ T383838core:barcode β”‚ QR / barcode scanning (channel-share QR codes) β”‚
β”‚ T383838core:nfc β”‚ NFC read/write support β”‚
β”‚ T383838core:takserver β”‚ Embedded TAK server integration β”‚
β”‚ T383838core:testing β”‚ Test utilities β”‚
β”‚ T383838core:konsist β”‚ Konsist architecture/convention tests β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Protobuf models are no longer a local module β€” they come from the external T383838org.meshtastic:protobufs Maven artifact (pinned in T383838gradle/libs.versions.toml).

KMP Source Sets

Each module uses the standard KMP source set hierarchy:

T282828
src/
β”œβ”€β”€ commonMain/ ← Shared code (all platforms)
β”œβ”€β”€ commonTest/ ← Shared tests
β”œβ”€β”€ androidMain/ ← Android-specific
β”œβ”€β”€ jvmMain/ ← Desktop JVM-specific
β”œβ”€β”€ iosMain/ ← iOS-specific
└── jvmTest/ ← Desktop test host

Golden Rules:
β€’ No T383838android.* imports in T383838commonMain
β€’ Platform-specific code goes in appropriate source set
β€’ Prefer interfaces + DI over T383838expect/T383838actual for complex behaviors
β€’ Use T383838expect/T383838actual only for simple declarations

Dependency Injection

The project uses Koin with annotation processing:
β€’ T383838@Module, T383838@Single, T383838@Factory annotations
β€’ T383838@ComponentScan for automatic registration
β€’ Feature modules export their own T383838Feature*Module class
β€’ App/Desktop compose all modules in their root DI configuration

Radio Control

Features issue radio commands through T383838RadioController (T383838core:repository), a composite of four
focused sub-interfaces so callers can depend on just the slice they need:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Sub-interface β”‚ Responsibility β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T383838AdminController β”‚ Config, channels, owner, device lifecycle, T383838editSettings { } transactions β”‚
β”‚ T383838MessagingController β”‚ Send packets, reactions, shared contacts β”‚
β”‚ T383838NodeController β”‚ Favorite, ignore, mute, remove nodes β”‚
β”‚ T383838QueryController β”‚ Telemetry, traceroute, position/user-info queries β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

T383838RadioControllerImpl (T383838core:service) is the in-process composition root for all targets
(Desktop, iOS, single-process Android). It assembles the four sub-controllers via Kotlin interface
delegation and adds the cross-cutting concerns (connection state, packet-id, location,
device-address switching). Commands are direct suspend calls; admin writes are fire-and-forget
because the device is the source of truth (local persistence is an optimistic cache). The layered
shape mirrors the meshtastic-sdk
T383838AdminApi/T383838TelemetryApi design to ease a future SDK migration.

Service Repository

T383838ServiceRepository is the reactive bridge between the mesh service and all feature/UI layers.
It is decomposed into focused provider interfaces following the Interface Segregation Principle:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Interface β”‚ Responsibility β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T383838ConnectionStateProvider β”‚ Read-only T383838connectionState: StateFlow<ConnectionState> β”‚
β”‚ T383838TracerouteResponseProvider β”‚ Traceroute response state + clear β”‚
β”‚ T383838NeighborInfoResponseProvider β”‚ Neighbor info response state + clear β”‚
β”‚ T383838ServiceStateWriter β”‚ Write-side for handlers (set, emit, clear*) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

T383838ServiceRepository extends all four interfaces β€” consumers inject the narrowest interface
they actually need. For example, T383838ContactsViewModel injects only T383838ConnectionStateProvider
rather than the entire T383838ServiceRepository, preventing accidental access to write operations
from UI code. T383838RadioController also extends T383838ConnectionStateProvider so VMs that already
inject a controller sub-interface can read connection state without a separate dependency.

Navigation

Navigation uses Navigation 3 with typed routes:
β€’ All routes defined in T383838core/navigation/Routes.kt
β€’ Routes are T383838@Serializable data classes/objects
β€’ Deep links resolved through T383838DeepLinkRouter
β€’ Each feature registers its own navigation entries

See Navigation & Deep Links for details.


Served by rngit 1.5.0 - Generated in 0.05s